/** @file

  Copyright (C) 2022 - 2023, Phytium Technology Co., Ltd. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "WarnAlarm.h"

typedef struct warn_alarm_fun{
  VOID (*Alarm)(UINTN ErrorType);
}warn_alarm_fun_t;

VOID 
SendCpldCtr(
  UINT32 cmd
  )
{
  UINT32 i;
  DEBUG((EFI_D_INFO, "send cmd to cpld : %d \n", cmd));
  //start
  MmioWrite32(PWR_CTR0_REG, 0x1);
  MicroSecondDelay(1000);
  for(i = 0; i < cmd; i++){
  MmioWrite32(PWR_CTR1_REG, 0x1);
  MicroSecondDelay(2000);
  MmioWrite32(PWR_CTR1_REG, 0x0);
  MicroSecondDelay(1000);
  }
  //end
  MicroSecondDelay(2000);
  MmioWrite32(PWR_CTR0_REG, 0x0);
}
/*
VOID
Pullupshort(
  VOID
  )
{
#if 0
  UINT32  PullUp;

//Output high level 400ms
  PullUp = MmioRead32(GPIO_0_BASE + GPIO_SWPORT_DR);
  PullUp |= PULL_UP;
  MmioWrite32(GPIO_0_BASE + GPIO_SWPORT_DR, PullUp);
#endif

#if 1
  MmioWrite32(PWR_CTR1_REG, 0x1);
#endif

  MicroSecondDelay(400000);
}

VOID
Pulluplong(
  VOID
  )
{
#if 0
  UINT32  PullUp;

//Output high level 800ms
  PullUp = MmioRead32(GPIO_0_BASE + GPIO_SWPORT_DR);
  PullUp |= PULL_UP;
  MmioWrite32(GPIO_0_BASE + GPIO_SWPORT_DR, PullUp);
#endif

#if 1
  MmioWrite32(PWR_CTR1_REG, 0x1);
#endif

  MicroSecondDelay(800000);
}
*/

VOID
Pulldown(
  VOID
  )
{
#if 0 
  UINT32  PullDown;

//Output low level 100ms
  PullDown = MmioRead32(GPIO_0_BASE + GPIO_SWPORT_DR);
  CLEARBIT(PullDown,2);
  MmioWrite32(GPIO_0_BASE + GPIO_SWPORT_DR, PullDown);
#endif

#if 1
  MmioWrite32(PWR_CTR1_REG, 0x0);
#endif

  MicroSecondDelay(100000);
}

VOID
WarnAlarm(
  VOID
  )
{
  EFI_STATUS	   Status1;
  //EFI_STATUS	   Status2;
  EFI_STATUS     Status;

  UINTN  HandleIndex;
  UINTN  HandleIndex1;
  UINTN  NumHandlesPci;
  UINTN  NumHandlesDisk;
  UINTN  NumHandlesUsb;
  //UINTN  NumHandlesGop;
  UINTN  PciDevicesFlag;

  UINTN  GOP,Brige,ATA,Usb,GOPDriver;//,UsbDriver;
  GOP   = 0;
  Brige = 0;
  ATA   = 0;
  Usb   = 0;
  GOPDriver = 0;
  //UsbDriver = 0;

  EFI_HANDLE  *ControllerHandlesPci  = NULL;
  EFI_HANDLE  *ControllerHandlesDisk = NULL;
  EFI_HANDLE  *ControllerHandlesUsb = NULL;
  //EFI_HANDLE  *ControllerHandlesGop = NULL;

  UINTN  GopFlag;
  UINTN  BrigeFlag;
  UINTN  ATAFlag;
  UINTN  UsbFlag;
  //UINTN  i= 0;

  ATAFlag    = 0X106;
  GopFlag    = 0x3;
  BrigeFlag  = 0X604;
  UsbFlag    = 0XC03;

  //EFI_USB2_HC_PROTOCOL       *UsbHcPro  = NULL;
  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GopPro       = NULL;
  EFI_PCI_IO_PROTOCOL           *PciPro       = NULL;
  //EFI_DISK_INFO_PROTOCOL        *DiskInfoPro  = NULL;
  EFI_USB_IO_PROTOCOL           *UsbIoPro     = NULL;

#if 0
//Configuration GPIO_0_A2 reuse
  Value = MmioRead32(PIN_REUSE_CTL+GPIO_O_A2_REUSE);
  SETBIT(Value,18);
  SETBIT(Value,16);
  CLEARBIT(Value,19);
  CLEARBIT(Value,17);
  MmioWrite32(PIN_REUSE_CTL+GPIO_O_A2_REUSE,Value);

//Configuration GPIO_0_A2 output
  Value = MmioRead32(GPIO_0_BASE+GPIO_SWPORT_DDR);
  SETBIT(Value,2);
  MmioWrite32(GPIO_0_BASE+GPIO_SWPORT_DDR,Value);

  Pulldown();
#endif

  /* Juadge whether there is a GOP device*/
  Status = gBS->LocateHandleBuffer(
                        ByProtocol,
                        &gEfiPciIoProtocolGuid,
                        NULL,
                        &NumHandlesPci,
                        &ControllerHandlesPci
                        );

  if(Status == EFI_NOT_FOUND){
      DEBUG((EFI_D_ERROR,"Don't Find PCI Devices"));
  }

  //DEBUG((EFI_D_INFO,"the PCI handle number is %d\n",NumHandlesPci));
  //DEBUG((EFI_D_INFO,"the USB handle number is %d\n",NumHandlesUsb));

  for(HandleIndex = 0; HandleIndex < NumHandlesPci ; HandleIndex++) {
          Status = gBS->HandleProtocol(
                         ControllerHandlesPci[HandleIndex],
                         &gEfiPciIoProtocolGuid,
                         (VOID **)&PciPro
                         );
    //DEBUG((EFI_D_INFO,"the Handle Index is %x\n",HandleIndex));
    Status = PciPro->Pci.Read(
                        PciPro,
                        EfiPciIoWidthUint32,
                        8,
                        1,
                        &PciDevicesFlag
                        );
    //DEBUG((EFI_D_ERROR,"PciDevicesFlag >> 16 is 0x%x \n",PciDevicesFlag));
    //DEBUG((EFI_D_ERROR,"PciDevicesFlag >> 16 is 0x%x \n",(PciDevicesFlag >> 16)));

    if((PciDevicesFlag >> 24) == GopFlag){
      GOP++;
      /* Judge whether GOP initialzation failed*/
      Status = gBS->LocateProtocol(
                      &gEfiGraphicsOutputProtocolGuid,
                      NULL,
                      (VOID **)&GopPro
                      );
      //DEBUG((EFI_D_INFO,"STATUS is %r\n",Status));
      if(Status == EFI_SUCCESS){
        GOPDriver++;
      }
    }

    if((PciDevicesFlag >> 16) == BrigeFlag){
      Brige++;
    }

    if((PciDevicesFlag >> 16) == ATAFlag){
      /* Judge whether there is a hard disk*/

      Status = gBS->LocateHandleBuffer(
                      ByProtocol,
                      &gEfiDiskInfoProtocolGuid,
                      NULL,
                      &NumHandlesDisk,
                      &ControllerHandlesDisk
                      );
     DEBUG((EFI_D_INFO,"NumHandlesDisk  is %d\n",NumHandlesDisk));

     for (HandleIndex1 = 0; HandleIndex1 < NumHandlesDisk ; HandleIndex1++){
       Status1 = gBS->HandleProtocol(
                      ControllerHandlesDisk[HandleIndex1],
                      &gEfiUsbIoProtocolGuid,
                      (VOID **)&UsbIoPro
                      );
       DEBUG((EFI_D_INFO,"Handle DiskInfo Protocol Status is %r\n",Status));
       DEBUG((EFI_D_INFO,"Handle UsbIo Protocol Status is %r\n",Status1));

       if (Status == EFI_SUCCESS && Status1 != EFI_SUCCESS){
         ATA++;
         DEBUG((EFI_D_INFO,"Find Hard Disk\n"));
      }
     }
    }
    if((PciDevicesFlag >> 16) == UsbFlag){
        Usb++;
        /* Judeg whether the  usb controller is abnormal*/
        //DEBUG((EFI_D_INFO,"USB Num is %x\n",Usb));
/*
        Status = gBS->LocateProtocol(
                       &gEfiUsb2HcProtocolGuid,
                       NULL,
                       (VOID **)&UsbHcPro
                       );
        DEBUG((EFI_D_INFO,"usb STATUS is %r\n",Status));
        if(Status == EFI_SUCCESS){
            UsbDriver++;
            DEBUG((EFI_D_INFO,"USB Controller Normal\n"));
        }
*/
    }

  }
  	Status = gBS->LocateHandleBuffer(
					ByProtocol,
					&gEfiUsb2HcProtocolGuid,
					NULL,
					&NumHandlesUsb,
					&ControllerHandlesUsb
					);
  
  DEBUG((EFI_D_INFO,"Brige Num is %x\n",Brige));
  DEBUG((EFI_D_INFO,"GOP Num is %x\n",GOP));
  DEBUG((EFI_D_INFO,"USB Num is %x\n",Usb));
  DEBUG((EFI_D_INFO,"USB Controller Num is %x\n",NumHandlesUsb));

  if(ATA == 0){
    Alarm(ERROR_TYPE5);
  }
  if(Usb != NumHandlesUsb){
     Alarm(ERROR_TYPE6);
  }
  if(GOP == 0){
    Alarm(ERROR_TYPE3);
  }else{
     DEBUG((EFI_D_INFO,"Graphics Card Found\n"));
  }
  if(GOPDriver == 0){
    Alarm(ERROR_TYPE4);
  }else{
     DEBUG((EFI_D_INFO,"Graphics Card Initialization Success\n"));
  }
  if(Brige == 0){
    DEBUG((EFI_D_ERROR,"No PciBrige Found---- \n\n\n"));
  }

}

VOID
AlarmCpld(
  UINTN   ErrorType
  )
{
  MmioWrite32(PWR_CTR0_REG, 0x0);

  switch(ErrorType)
  {
  case ERROR_TYPE0:  //3 short 1 long
         SendCpldCtr(16);
         break;

  case ERROR_TYPE1:  //1 short 1 long
         SendCpldCtr(17);
         break;

  case ERROR_TYPE2:  //4 short
         SendCpldCtr(18);
         break;

  case ERROR_TYPE3:  //1 long 2 short
         SendCpldCtr(19);
         DEBUG((EFI_D_ERROR,"No Graphics Card Found\n"));
         break;

  case ERROR_TYPE4:  //1 long 3 short
         SendCpldCtr(20);
         DEBUG((EFI_D_ERROR,"GOP Initialization Failed\n"));
         break;

  case ERROR_TYPE5:  //2 long 1 short
         SendCpldCtr(21);
         DEBUG((EFI_D_ERROR,"Don't Find A Hard Disk\n"));
         break;

  case ERROR_TYPE6:  //2 long 3 short
         SendCpldCtr(22);
         DEBUG((EFI_D_ERROR,"USB Controller Abnomaly\n"));
         break;

  case ERROR_TYPE7:  //5 short
         SendCpldCtr(23);
         break;
  default:
          Pulldown();
  }
}

static warn_alarm_fun_t warn_alarm_fun_cpld = {
    .Alarm = AlarmCpld
};

VOID
AlarmSe(
  UINTN   ErrorType
  )
{

  switch(ErrorType)
  {
    case ERROR_TYPE0:  //3 short 1 long
      SendSeCtr(0x20);
      break;

    case ERROR_TYPE1:  //1 short 1 long
      SendSeCtr(0x21);
      break;

    case ERROR_TYPE2:  //4 short
      SendSeCtr(0x22);
      break;

    case ERROR_TYPE3:  //1 long 2 short
      SendSeCtr(0x23);
      DEBUG((EFI_D_ERROR,"No Graphics Card Found\n"));
      break;

    case ERROR_TYPE4:  //1 long 3 short
      SendSeCtr(0x24);
      DEBUG((EFI_D_ERROR,"GOP Initialization Failed\n"));
      break;

    case ERROR_TYPE5:  //2 long 1 short
      SendSeCtr(0x25);
      DEBUG((EFI_D_ERROR,"Don't Find A Hard Disk\n"));
      break;

    case ERROR_TYPE6:  //2 long 3 short
      SendSeCtr(0x26);
      DEBUG((EFI_D_ERROR,"USB Controller Abnomaly\n"));
      break;

    case ERROR_TYPE7:  //5 short
      SendSeCtr(0x27);
      break;
    default:
      Pulldown();
  }
}

static warn_alarm_fun_t warn_alarm_fun_se = {
    .Alarm = AlarmSe
};

void * get_flag(void)
{
  switch(pm_get_s3_flag_source())
  {
    case 0:
      return &warn_alarm_fun_cpld;
    case 2:
      return &warn_alarm_fun_se;
    default:
      return &warn_alarm_fun_cpld;
    }

}

VOID
Alarm(
  UINTN ErrorType
  )
{
  //pwr_ctr_fun_t *pwr_flag_p = get_flag_fun();
  warn_alarm_fun_t *warn_alarm_fun_p = get_flag();

  if(NULL == warn_alarm_fun_p || NULL == warn_alarm_fun_p->Alarm){
    DEBUG((EFI_D_ERROR, "%a(),Line=%d\n", __FUNCTION__, __LINE__));
    while(1);
  }

  warn_alarm_fun_p->Alarm(ErrorType);
}

